From 5e79e298233eef980267969f89da7b650eab36d0 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Tue, 7 May 2024 10:52:45 +0200 Subject: [PATCH] Geometry: Start OnPickEvent refactoring. --- src/Model/Geometry/ProfileXYZ.py | 4 +- src/View/Geometry/Profile/Plot.py | 171 +++++++++++++++++++++++----- src/View/Geometry/Profile/Window.py | 19 +++- src/View/Tools/PamhyrPlot.py | 25 +++- 4 files changed, 187 insertions(+), 32 deletions(-) diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index f3ebe88f..eae7f54d 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -457,12 +457,12 @@ class ProfileXYZ(Profile, SQLSubModel): station.append(station_i) z_min = self.z_min() - index_profile_z_min = list( + index_profile_z_min = next( filter( lambda z: z[1] == z_min, enumerate(self.z()) ) - )[0] + ) constant = station[index_profile_z_min[0]] return list(map(lambda s: s - constant, station)) diff --git a/src/View/Geometry/Profile/Plot.py b/src/View/Geometry/Profile/Plot.py index 6cd62adf..b5d16734 100644 --- a/src/View/Geometry/Profile/Plot.py +++ b/src/View/Geometry/Profile/Plot.py @@ -18,14 +18,18 @@ import logging +from math import dist, sqrt + from tools import timer, trace from View.Tools.PamhyrPlot import PamhyrPlot from View.Tools.Plot.OnPickEvent import OnpickEvent from PyQt5.QtCore import ( - QCoreApplication + Qt, QCoreApplication, QItemSelectionModel ) +from PyQt5.QtWidgets import QApplication + _translate = QCoreApplication.translate logger = logging.getLogger() @@ -56,6 +60,117 @@ class Plot(PamhyrPlot): self._isometric_axis = False + self.hl_points = [] + self.highlight = ( + [], # Points list to highlight + None # Water level (z) + ) + + def onpick(self, event): + if event.mouseevent.inaxes != self.canvas.axes: + return + + modifiers = QApplication.keyboardModifiers() + if modifiers != Qt.ControlModifier: + return + + points, z = self.highlight + + ind, point = self._closer_point(event) + + self.highlight = ([point], z) + self._select_in_table(ind) + + self.update() + return + + def onclick(self, event): + if event.inaxes != self.canvas.axes: + return + + modifiers = QApplication.keyboardModifiers() + if modifiers != Qt.ShiftModifier: + return + + points, z = self.highlight + + # Compute largeur au miroir + + self.highlight = (points, z) + + self.update() + return + + def select_points_from_indexes(self, indexes): + data = self.data + _, z = self.highlight + + points = list( + map( + lambda e: e[1], + filter( + lambda e: e[0] in indexes, + enumerate( + zip(data.get_station(), data.z()) + ) + ) + ) + ) + + self.highlight = (points, z) + self.update() + + def _select_in_table(self, ind): + if self._table is not None: + self._table.blockSignals(True) + self._table.setFocus() + + selection = self._table.selectionModel() + index = self._table.model().index(ind, 0) + selection.select( + index, + QItemSelectionModel.Rows | + QItemSelectionModel.ClearAndSelect | + QItemSelectionModel.Select + ) + + self._table.scrollTo(index) + self._table.blockSignals(False) + + def _closer_point(self, event): + points_ind = event.ind + axes = self.canvas.axes + bx, by = axes.get_xlim(), axes.get_ylim() + ratio = (bx[0] - bx[1]) / (by[0] - by[1]) + + x = event.artist.get_xdata() + y = event.artist.get_ydata() + + # points = filter( + # lambda e: e[0] in points_ind, + # enumerate(zip(x, y)) + # ) + points = enumerate(zip(x, y)) + + mx = event.mouseevent.xdata + my = event.mouseevent.ydata + + def dist_mouse(point): + x, y = point[1] + d = ( + sqrt( + (((mx - x) / ratio) ** 2) + + ((my - y) ** 2) + ) + ) + return d + + closer = min( + points, key=dist_mouse + ) + + return closer + @timer def draw(self): self.init_axes() @@ -65,19 +180,26 @@ class Plot(PamhyrPlot): x_carto = self.data.x() y_carto = self.data.y() - if (len(x_carto) < 3 or len(y_carto) < 3 or - len(x) < 3): + if (len(x_carto) < 3 + or len(y_carto) < 3 + or len(x) < 3): # Noting to do in this case return - gl = map(lambda p: p.name, self.data.points) - self.profile_line2D, = self.canvas.axes.plot( x, y, color=self.color_plot, lw=1.5, markersize=7, marker='+', picker=30 ) + self.draw_annotation(x, y) + self.draw_hightligth() + + self.idle() + + def draw_annotation(self, x, y): + gl = map(lambda p: p.name, self.data.points) + # Add label on graph self.annotation = [] for i, name in enumerate(list(gl)): @@ -113,30 +235,25 @@ class Plot(PamhyrPlot): self.canvas.axes.set_facecolor('#F9F9F9') self.canvas.figure.patch.set_facecolor('white') - self.onpick_event = OnpickEvent( - self.canvas.axes, - x, y, x_carto, y_carto, - self._table - ) - self.canvas.figure.canvas\ - .mpl_connect( - 'pick_event', - self.onpick_event.onpick - ) + def draw_hightligth(self): + points, z = self.highlight + for p in self.hl_points: + p[0].set_data([], []) - self.onclick_event = OnpickEvent( - self.canvas.axes, - x, y, x_carto, y_carto, - self._table - ) - self.canvas.figure.canvas\ - .mpl_connect( - 'button_press_event', - self.onclick_event.onclick - ) + self.hl_points = [] - self.idle() + for x, y in points: + self.hl_points.append( + self.canvas.axes.plot( + x, y, + color=self.color_plot_highlight, + lw=1.5, markersize=7, marker='+', + picker=30 + ) + ) @timer def update(self): - self.draw() + self.draw_hightligth() + + self.update_idle() diff --git a/src/View/Geometry/Profile/Window.py b/src/View/Geometry/Profile/Window.py index 9a274c9f..d8f2da07 100644 --- a/src/View/Geometry/Profile/Window.py +++ b/src/View/Geometry/Profile/Window.py @@ -131,8 +131,17 @@ class ProfileWindow(PamhyrWindow): self.find(QAction, action)\ .triggered.connect(actions[action]) + table = self.find(QTableView, f"tableView") + table.selectionModel()\ + .selectionChanged\ + .connect(self.update_points_selection) + self._tablemodel.dataChanged.connect(self.update) + def update_points_selection(self): + rows = self.index_selected_rows() + self._plot.select_points_from_indexes(rows) + def update(self): self.update_plot() self._propagate_update(key=Modules.GEOMETRY) @@ -140,7 +149,6 @@ class ProfileWindow(PamhyrWindow): def update_plot(self): self._tablemodel.blockSignals(True) - # TODO: Do not rebuild all graph self._plot.update() self._tablemodel.blockSignals(False) @@ -154,6 +162,15 @@ class ProfileWindow(PamhyrWindow): return rows[0].row() + def index_selected_rows(self): + table = self.find(QTableView, "tableView") + return list( + map( + lambda r: r.row(), + table.selectionModel().selectedRows() + ) + ) + def add(self): table = self.find(QTableView, "tableView") if len(table.selectedIndexes()) == 0: diff --git a/src/View/Tools/PamhyrPlot.py b/src/View/Tools/PamhyrPlot.py index 08232273..4b0c6f35 100644 --- a/src/View/Tools/PamhyrPlot.py +++ b/src/View/Tools/PamhyrPlot.py @@ -67,6 +67,23 @@ class PamhyrPlot(APlot): self._table = table self._parent = parent + self._init_event() + self._init_default_value() + + super(PamhyrPlot, self).__init__(data=data) + + def _init_event(self): + connector = { + 'pick_event': self.onpick, + 'button_press_event': self.onclick, + } + + for event in connector: + self.canvas.mpl_connect( + event, connector[event] + ) + + def _init_default_value(self): self._label_x = "X" self._label_y = "Y" @@ -83,8 +100,6 @@ class PamhyrPlot(APlot): self._current_data = None #: Current data identifier self._current_data_update = False - super(PamhyrPlot, self).__init__(data=data) - @property def canvas(self): return self._canvas @@ -209,3 +224,9 @@ class PamhyrPlot(APlot): shadow=True, fontsize=8 ) + + def onpick(self, event): + return + + def onclick(self, event): + return