diff --git a/invesalius/data/slice_.py b/invesalius/data/slice_.py index f3d377d..d128783 100644 --- a/invesalius/data/slice_.py +++ b/invesalius/data/slice_.py @@ -434,7 +434,7 @@ class Slice(object): thresh_min, thresh_max = self.current_mask.edition_threshold_range if hasattr(position, '__iter__'): - py, px = position + px, py = position if orientation == 'AXIAL': sx = self.spacing[0] sy = self.spacing[1] diff --git a/invesalius/data/styles.py b/invesalius/data/styles.py index 8f00776..b777961 100644 --- a/invesalius/data/styles.py +++ b/invesalius/data/styles.py @@ -76,6 +76,7 @@ def get_LUT_value(data, window, level): data.shape = shape return data + class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage): def __init__(self, viewer): self.right_pressed = False @@ -213,52 +214,18 @@ class CrossInteractorStyle(DefaultInteractorStyle): def ChangeCrossPosition(self, iren): mouse_x, mouse_y = iren.GetEventPosition() - ren = iren.GetRenderWindow().GetRenderers().GetFirstRenderer() - self.picker.Pick(mouse_x, mouse_y, 0, ren) - - # Get in what slice data the click occurred - # pick to get click position in the 3d world - coord_cross = self.get_coordinate_cursor() - position = self.slice_actor.GetInput().FindPoint(coord_cross) - # Forcing focal point to be setted in the center of the pixel. - coord_cross = self.slice_actor.GetInput().GetPoint(position) - - coord = self.calcultate_scroll_position(position) - Publisher.sendMessage('Update cross position', coord_cross) + wx, wy, wz = self.viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker) + px, py = self.viewer.get_slice_pixel_coord_by_world_pos(wx, wy, wz) + coord = self.viewer.calcultate_scroll_position(px, py) + Publisher.sendMessage('Update cross position', (wx, wy, wz)) self.ScrollSlice(coord) Publisher.sendMessage('Set ball reference position based on bound', - coord_cross) - Publisher.sendMessage('Set camera in volume', coord_cross) + (wx, wy, wz)) + Publisher.sendMessage('Set camera in volume', (wx, wy, wz)) Publisher.sendMessage('Render volume viewer') iren.Render() - - def calcultate_scroll_position(self, position): - # Based in the given coord (x, y, z), returns a list with the scroll positions for each - # orientation, being the first position the sagital, second the coronal - # and the last, axial. - - if self.orientation == 'AXIAL': - image_width = self.slice_actor.GetInput().GetDimensions()[0] - axial = self.slice_data.number - coronal = position / image_width - sagital = position % image_width - - elif self.orientation == 'CORONAL': - image_width = self.slice_actor.GetInput().GetDimensions()[0] - axial = position / image_width - coronal = self.slice_data.number - sagital = position % image_width - - elif self.orientation == 'SAGITAL': - image_width = self.slice_actor.GetInput().GetDimensions()[1] - axial = position / image_width - coronal = position % image_width - sagital = self.slice_data.number - - return sagital, coronal, axial - def ScrollSlice(self, coord): if self.orientation == "AXIAL": Publisher.sendMessage(('Set scroll position', 'SAGITAL'), @@ -276,18 +243,6 @@ class CrossInteractorStyle(DefaultInteractorStyle): Publisher.sendMessage(('Set scroll position', 'SAGITAL'), coord[0]) - def get_coordinate_cursor(self): - # Find position - x, y, z = self.picker.GetPickPosition() - bounds = self.viewer.slice_data.actor.GetBounds() - if bounds[0] == bounds[1]: - x = bounds[0] - elif bounds[2] == bounds[3]: - y = bounds[2] - elif bounds[4] == bounds[5]: - z = bounds[4] - return x, y, z - class WWWLInteractorStyle(DefaultInteractorStyle): """ @@ -791,21 +746,13 @@ class EditorInteractorStyle(DefaultInteractorStyle): #i.cursor.Show(0) slice_data.cursor.Show() - self.picker.Pick(mouse_x, mouse_y, 0, render) - - coord = self.get_coordinate_cursor() - position = slice_data.actor.GetInput().FindPoint(coord) + wx, wy, wz = viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker) + position = viewer.get_slice_pixel_coord_by_world_pos(wx, wy, wz) - if position != -1: - coord = slice_data.actor.GetInput().GetPoint(position) - - slice_data.cursor.SetPosition(coord) cursor = slice_data.cursor radius = cursor.radius - if position < 0: - position = viewer.calculate_matrix_position(coord) - + slice_data.cursor.SetPosition((wx, wy, wz)) viewer.slice_.edit_mask_pixel(operation, cursor.GetPixels(), position, radius, viewer.orientation) #viewer._flush_buffer = True @@ -842,39 +789,19 @@ class EditorInteractorStyle(DefaultInteractorStyle): elif operation == const.BRUSH_DRAW and iren.GetControlKey(): operation = const.BRUSH_ERASE - # TODO: Improve! - #for i in self.slice_data_list: - #i.cursor.Show(0) - - self.picker.Pick(mouse_x, mouse_y, 0, render) - - #if (self.pick.GetViewProp()): - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) - #else: - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) - - coord = self.get_coordinate_cursor() - position = viewer.slice_data.actor.GetInput().FindPoint(coord) - - # when position == -1 the cursos is not over the image, so is not - # necessary to set the cursor position to world coordinate center of - # pixel from slice image. - if position != -1: - coord = slice_data.actor.GetInput().GetPoint(position) - slice_data.cursor.SetPosition(coord) - #self.__update_cursor_position(slice_data, coord) + wx, wy, wz = viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker) + slice_data.cursor.SetPosition((wx, wy, wz)) if (self.left_pressed): cursor = slice_data.cursor - position = slice_data.actor.GetInput().FindPoint(coord) radius = cursor.radius - if position < 0: - position = viewer.calculate_matrix_position(coord) + position = viewer.get_slice_pixel_coord_by_world_pos(wx, wy, wz) + slice_data.cursor.SetPosition((wx, wy, wz)) viewer.slice_.edit_mask_pixel(operation, cursor.GetPixels(), - position, radius, self.orientation) - # TODO: To create a new function to reload images to viewer. + position, radius, viewer.orientation) + viewer.OnScrollBar(update3D=False) else: @@ -924,18 +851,6 @@ class EditorInteractorStyle(DefaultInteractorStyle): else: self.OnScrollBackward(obj, evt) - def get_coordinate_cursor(self): - # Find position - x, y, z = self.picker.GetPickPosition() - bounds = self.viewer.slice_data.actor.GetBounds() - if bounds[0] == bounds[1]: - x = bounds[0] - elif bounds[2] == bounds[3]: - y = bounds[2] - elif bounds[4] == bounds[5]: - z = bounds[4] - return x, y, z - class WatershedProgressWindow(object): def __init__(self, process): @@ -1153,28 +1068,15 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): render = iren.FindPokedRenderer(mouse_x, mouse_y) slice_data = viewer.get_slice_data(render) - # TODO: Improve! - #for i in self.slice_data_list: - #i.cursor.Show(0) - slice_data.cursor.Show() - - self.picker.Pick(mouse_x, mouse_y, 0, render) - - coord = self.get_coordinate_cursor() - position = slice_data.actor.GetInput().FindPoint(coord) - - if position != -1: - coord = slice_data.actor.GetInput().GetPoint(position) + coord = self.viewer.get_coordinate_cursor(mouse_x, mouse_y, picker=None) + position = self.viewer.get_slice_pixel_coord_by_screen_pos(mouse_x, mouse_y, self.picker) + slice_data.cursor.Show() slice_data.cursor.SetPosition(coord) cursor = slice_data.cursor - position = slice_data.actor.GetInput().FindPoint(coord) radius = cursor.radius - if position < 0: - position = viewer.calculate_matrix_position(coord) - operation = self.config.operation if operation == BRUSH_FOREGROUND: @@ -1213,31 +1115,13 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): render = iren.FindPokedRenderer(mouse_x, mouse_y) slice_data = viewer.get_slice_data(render) - # TODO: Improve! - #for i in self.slice_data_list: - #i.cursor.Show(0) - - self.picker.Pick(mouse_x, mouse_y, 0, render) - - #if (self.pick.GetViewProp()): - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) - #else: - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) - - coord = self.get_coordinate_cursor() - position = viewer.slice_data.actor.GetInput().FindPoint(coord) - - # when position == -1 the cursos is not over the image, so is not - # necessary to set the cursor position to world coordinate center of - # pixel from slice image. - if position != -1: - coord = slice_data.actor.GetInput().GetPoint(position) + coord = self.viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker) slice_data.cursor.SetPosition(coord) - #self.__update_cursor_position(slice_data, coord) if (self.left_pressed): cursor = slice_data.cursor - position = slice_data.actor.GetInput().FindPoint(coord) + position = self.viewer.get_slice_pixel_coord_by_world_pos(*coord) + print ">>>", position radius = cursor.radius if position < 0: @@ -1344,18 +1228,6 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): Publisher.sendMessage('Reload actual slice') - def get_coordinate_cursor(self): - # Find position - x, y, z = self.picker.GetPickPosition() - bounds = self.viewer.slice_data.actor.GetBounds() - if bounds[0] == bounds[1]: - x = bounds[0] - elif bounds[2] == bounds[3]: - y = bounds[2] - elif bounds[4] == bounds[5]: - z = bounds[4] - return x, y, z - def edit_mask_pixel(self, operation, n, index, position, radius, orientation): if orientation == 'AXIAL': mask = self.matrix[n, :, :] @@ -1366,7 +1238,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): spacing = self.viewer.slice_.spacing if hasattr(position, '__iter__'): - py, px = position + px, py = position if orientation == 'AXIAL': sx = spacing[0] sy = spacing[1] @@ -1804,24 +1676,10 @@ class FloodFillMaskInteractorStyle(DefaultInteractorStyle): viewer = self.viewer iren = viewer.interactor - mouse_x, mouse_y = iren.GetEventPosition() - render = iren.FindPokedRenderer(mouse_x, mouse_y) - slice_data = viewer.get_slice_data(render) - - self.picker.Pick(mouse_x, mouse_y, 0, render) - - coord = self.get_coordinate_cursor() - position = slice_data.actor.GetInput().FindPoint(coord) - - if position != -1: - coord = slice_data.actor.GetInput().GetPoint(position) - - if position < 0: - position = viewer.calculate_matrix_position(coord) + x, y, z = self.viewer.get_voxel_coord_by_screen_pos(mouse_x, mouse_y, self.picker) mask = self.viewer.slice_.current_mask.matrix[1:, 1:, 1:] - x, y, z = self.calcultate_scroll_position(position) if mask[z, y, x] < self.t0 or mask[z, y, x] > self.t1: return @@ -1878,43 +1736,6 @@ class FloodFillMaskInteractorStyle(DefaultInteractorStyle): self.viewer.slice_.current_mask.was_edited = True Publisher.sendMessage('Reload actual slice') - def get_coordinate_cursor(self): - # Find position - x, y, z = self.picker.GetPickPosition() - bounds = self.viewer.slice_data.actor.GetBounds() - if bounds[0] == bounds[1]: - x = bounds[0] - elif bounds[2] == bounds[3]: - y = bounds[2] - elif bounds[4] == bounds[5]: - z = bounds[4] - return x, y, z - - def calcultate_scroll_position(self, position): - # Based in the given coord (x, y, z), returns a list with the scroll positions for each - # orientation, being the first position the sagital, second the coronal - # and the last, axial. - - if self.orientation == 'AXIAL': - image_width = self.slice_actor.GetInput().GetDimensions()[0] - axial = self.slice_data.number - coronal = position / image_width - sagital = position % image_width - - elif self.orientation == 'CORONAL': - image_width = self.slice_actor.GetInput().GetDimensions()[0] - axial = position / image_width - coronal = self.slice_data.number - sagital = position % image_width - - elif self.orientation == 'SAGITAL': - image_width = self.slice_actor.GetInput().GetDimensions()[1] - axial = position / image_width - coronal = position % image_width - sagital = self.slice_data.number - - return sagital, coronal, axial - class RemoveMaskPartsInteractorStyle(FloodFillMaskInteractorStyle): def __init__(self, viewer): @@ -1989,7 +1810,7 @@ class SelectMaskPartsInteractorStyle(DefaultInteractorStyle): iren = self.viewer.interactor mouse_x, mouse_y = iren.GetEventPosition() - x, y, z = self.viewer.get_voxel_clicked(mouse_x, mouse_y, self.picker) + x, y, z = self.viewer.get_voxel_coord_by_screen_pos(mouse_x, mouse_y, self.picker) mask = self.viewer.slice_.current_mask.matrix[1:, 1:, 1:] diff --git a/invesalius/data/viewer_slice.py b/invesalius/data/viewer_slice.py index 581efb9..f61a9bd 100755 --- a/invesalius/data/viewer_slice.py +++ b/invesalius/data/viewer_slice.py @@ -940,25 +940,23 @@ class Viewer(wx.Panel): # WARN: Return the only slice_data used in this slice_viewer. return self.slice_data - def calcultate_scroll_position(self, position): - # Based in the given coord (x, y, z), returns a list with the scroll positions for each + def calcultate_scroll_position(self, x, y): + # Based in the given coord (x, y), returns a list with the scroll positions for each # orientation, being the first position the sagital, second the coronal # and the last, axial. - image_width = self.slice_.buffer_slices[self.orientation].image.shape[1] - if self.orientation == 'AXIAL': axial = self.slice_data.number - coronal = position / image_width - sagital = position % image_width + coronal = y + sagital = x elif self.orientation == 'CORONAL': - axial = position / image_width + axial = y coronal = self.slice_data.number - sagital = position % image_width + sagital = x elif self.orientation == 'SAGITAL': - axial = position / image_width - coronal = position % image_width + axial = y + coronal = x sagital = self.slice_data.number return sagital, coronal, axial @@ -975,13 +973,28 @@ class Viewer(wx.Panel): elif self.orientation == 'SAGITAL': mx = round((y - yi)/self.slice_.spacing[1], 0) my = round((z - zi)/self.slice_.spacing[2], 0) - return my, mx + return mx, my - def get_coordinate_cursor(self, picker=None): - # Find position + def get_coordinate_cursor(self, mx, my, picker=None): + """ + Given the mx, my screen position returns the x, y, z position in world + coordinates. + + Parameters + mx (int): x position. + my (int): y position + picker: the picker used to get calculate the voxel coordinate. + + Returns: + world coordinate (x, y, z) + """ if picker is None: picker = self.pick + slice_data = self.slice_data + renderer = slice_data.renderer + + picker.Pick(mx, my, 0, renderer) x, y, z = picker.GetPickPosition() bounds = self.slice_data.actor.GetBounds() if bounds[0] == bounds[1]: @@ -1029,10 +1042,10 @@ class Viewer(wx.Panel): return x, y, z - def get_voxel_clicked(self, mx, my, picker=None): + def get_voxel_coord_by_screen_pos(self, mx, my, picker=None): """ - Given the (mx, my) mouse clicked position returns the voxel coordinate - of the voxel at (that mx, my) position. + Given the (mx, my) screen position returns the voxel coordinate + of the volume at (that mx, my) position. Parameters: mx (int): x position. @@ -1046,23 +1059,86 @@ class Viewer(wx.Panel): if picker is None: picker = self.pick + wx, wy, wz = self.get_coordinate_cursor(mx, my, picker) + x, y, z = self.get_voxel_coord_by_world_pos(wx, wy, wz) + + return (x, y, z) + + def get_voxel_coord_by_world_pos(self, wx, wy, wz): + """ + Given the (x, my) screen position returns the voxel coordinate + of the volume at (that mx, my) position. + + Parameters: + wx (float): x position. + wy (float): y position + wz (float): z position + + Returns: + voxel_coordinate (x, y, z): voxel coordinate inside the matrix. Can + be used to access the voxel value inside the matrix. + """ + px, py = self.get_slice_pixel_coord_by_world_pos(wx, wy, wz) + x, y, z = self.calcultate_scroll_position(px, py) + + return (x, y, z) + + + def get_slice_pixel_coord_by_screen_pos(self, mx, my, picker=None): + """ + Given the (mx, my) screen position returns the pixel coordinate + of the slice at (that mx, my) position. + + Parameters: + mx (int): x position. + my (int): y position + picker: the picker used to get calculate the pixel coordinate. + + Returns: + voxel_coordinate (x, y): voxel coordinate inside the matrix. Can + be used to access the voxel value inside the matrix. + """ + if picker is None: + picker = self.pick + + wx, wy, wz = self.get_coordinate_cursor(mx, my, picker) + return self.get_slice_pixel_coord_by_world_pos(wx, wy, wz) + + return px, py + + def get_slice_pixel_coord_by_world_pos(self, wx, wy, wz): + """ + Given the (wx, wy, wz) world position returns the pixel coordinate + of the slice at (that mx, my) position. + + Parameters: + mx (int): x position. + my (int): y position + picker: the picker used to get calculate the pixel coordinate. + + Returns: + voxel_coordinate (x, y): voxel coordinate inside the matrix. Can + be used to access the voxel value inside the matrix. + """ + coord = wx, wy, wz + px, py = self.calculate_matrix_position(coord) + + return px, py + + def get_coord_inside_volume(self, mx, my, picker=None): + if picker is None: + picker = self.pick + slice_data = self.slice_data renderer = slice_data.renderer - picker.Pick(mx, my, 0, renderer) - coord = self.get_coordinate_cursor(picker) position = slice_data.actor.GetInput().FindPoint(coord) if position != -1: coord = slice_data.actor.GetInput().GetPoint(position) - if position < 0: - position = viewer.calculate_matrix_position(coord) - - x, y, z = self.calcultate_scroll_position(position) - - return (x, y, z) + return coord def __bind_events(self): Publisher.subscribe(self.LoadImagedata, -- libgit2 0.21.2